from django.db import models
from pirate_consensus.models import Consensus, UpDownVote
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes import generic
import datetime
from django.utils.translation import ugettext as _
from django.contrib import admin
from pirate_signals.models import vote_created
from django.contrib.contenttypes.models import ContentType
import math, datetime 
from pirate_consensus.models import Rating, Spectrum

  
# Create your models here.
class Ranking(models.Model):
    content_type = models.ForeignKey(ContentType,
                                      verbose_name=_('content type'),
                                      related_name="content_type_set_for_%(class)s")
    object_pk = models.IntegerField(_('object ID'))
    content_object = generic.GenericForeignKey(ct_field="content_type", fk_field="object_pk")
    
    consensus_pk = models.IntegerField(_('consensus_object ID'))
    dimension = models.CharField(max_length=25)
    score = models.FloatField() 
    
    def __unicode__(self):
        return "%s: %s" % (self.dimension, self.score)
    
    def save(self, force_insert=False, force_update=False):
        super(Ranking, self).save(force_insert, force_update)
        if self.dimension == 'hot': 
            cons = Consensus.objects.get(pk=self.consensus_pk)
            cons.interest = self.score
            cons.save()
        elif self.dimension == 'cont':
            try: #object in question should have consensus associated with it
                cons = Consensus.objects.get(pk=self.consensus_pk)
                cons.controversy = self.score
                cons.save()
            except: #if not this is in error
                pass
            

def calc_new(obj):
    return 0


def calc_controversial(dt, spectrum, rating):
    x = 0 # weighted votes
    mag = 0 #magnitude of votes
    #compute the mean
    for k, num in spectrum: 
        x += k * num
        mag += num
    if mag != 0: 
        mean = x / mag
        #compute the sd
        tot = 0
        for k, num in spectrum: #TODO: INEFFICIENT, needs better solution
            for i in range(num): 
                tot += math.pow((k - mean),2)
        sd = math.sqrt(tot/mag)
    else: 
        mean = 0.0 
        sd = 0.0
    score = sd * math.log(mag) * dt
    
    return score

def calc_hot(dt, spectrum, rating):
    #get spectrum list ex: [(-5,246), (-4,45), ... ,(5,121)]
    x = 0
    for k, num in spectrum: 
        x += k * num
    r = 0.0
    tot = 0.0

    for k, weight, num in rating:
        r += k * num * weight
        tot += num
    if tot != 0: r = r/tot #get average rating
    else: r = 0.0
    
    if r != 0: x = x * r
    else: pass
    #general score according to up - vote, need to work in way to make neut important...
    if x > 0: y = 1
    elif x == 0: y = 0
    else: y = -1
    #now if the obj is siginficant, i.e. been viewed extensively we take into account it's popularity
    z = abs(x)
    #now calculate final score
    score = (3 * math.log(z) + y) * dt
    return score

#When a vote is created via the consensus engine, this callback updates
#the issue ranked score, for each dimension    
def vote_created_callback(sender, **kwargs):
    #udpate hot
    try:
        cons = kwargs.pop('parent',None)
        vt = kwargs.pop('vote_type',None)
        pis = cons.content_object #parent of the consensus object 
        #For the HOT dimension
        ###TODO: Only should rerank when a unique user creates a vote. If a user 
        ### has created a vote before it should not be counted toward the reranking.
        ### This closes a process that allows users to maliciously inflate hot ranking

        try: spectrum = cons.spectrum.get_list()
        except: #add spectrum to consensus if first vote
            sp = Spectrum()
            cons.spectrum = sp
            sp.save()
            cons.save()
            spectrum = cons.spectrum.get_list()
        try: rating = cons.rating.get_list()
        except: #add rating to consensus if first rating
            rt = Rating()
            cons.rating = rt
            rt.save()
            cons.save()
            rating = cons.rating.get_list()
        dt = cons.submit_date
        timeDiff = (dt  - datetime.datetime(2010, 7, 5, 20, 16, 19, 539498)).seconds
        timeNormFactor=(dt - datetime.datetime.now()).seconds
    
        dt=timeDiff/float(timeNormFactor)
    
        sols = [( ('hot', calc_hot(dt, spectrum, rating)), ('cont', calc_controversial(dt, spectrum, rating)) )	]

        ###I don't know why, but this fails if it's where it should be up above...    
        from pirate_ranking.models import Ranking         
        for scores in sols:
            for dim, sc in scores: 
                try: 
                    obj = Ranking.objects.get(object_pk=pis.id, dimension=dim)
                    obj.score = sc
                    obj.save()
                except:
                    contype = ContentType.objects.get_for_model(pis)
                    newrank = Ranking(content_object=pis,dimension=dim,score=sc,consensus_pk=cons.id,content_type=contype,object_pk=pis.id)
                    newrank.save()
    except:
        raise
            
    
vote_created.connect(vote_created_callback)
admin.site.register(Ranking)
